﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace WindowsGame1.GameComponents
{
    class EntityManager
    {
        Microsoft.Xna.Framework.Content.ContentManager content;
        public Room currentRoom;
        
        //ObjectList players
        PrototypeHero protoman;

        //stuff
        Texture2D background;

        //ObjectList enemies - enemies and traps?
        //ObjectList environment - walls and dumb furniture / inanimate
        List<CollidableObject> projectiles = new List<CollidableObject>(); //all non-touch based attacks
        //ObjectList item_entities - chests and loose items
        List<CollidableObject> enemies = new List<CollidableObject>(); //enemies and traps

        public void LoadTutorialRoom()
        {
            protoman = new PrototypeHero(this);
            //enemies.Add(new RunEnemy("smallsquaregoblin",new Vector2(300, 300), 5, 1, 300));
            enemies.Add(new RunEnemy());
            enemies.Add(new LordEnemy());
            enemies.Add(new WizRobeEnemy());
        }

        //eventually this should take less information because the lifespan should be stored in the projectile type
        public void Projectile(Microsoft.Xna.Framework.GameTime spawnTime, int lifespan, Microsoft.Xna.Framework.Vector2 position)
        {
            PrototypeProjectile protojectile = new PrototypeProjectile(spawnTime, lifespan);
            protojectile.SetPosition(position);
            protojectile.LoadContent(content);
        }

        public void Enemy()
        {
            //takes in an enemy, loads its content, adds it to the scene
        }

        public void CheckCollision()
        {
            //checks player collision against players and environment
            //checks enemy collision against enemies and environment
        }

        public void CheckDamage()
        {
            //checks projectile collision against players
            //checks projectile collision against enemies
            foreach (CollidableObject obj in projectiles)
            {
                foreach (CollidableObject obj_2 in enemies)
                {
                    if (obj != null && obj.IsAlive())
                    {
                        //if (obj.GetHitBox().Contains(obj_2.GetHitBox()))
                        //ACEY: Change GetHitBox to return either a Rectangle, or a struct made up of several Rectangles...
                        //it might be good to use a different rectangle class because the XNA one is based on POINTS and everything else is using Vectors
                        if (true)
                        {
                            Console.WriteLine("ouch");
                            obj_2.GetDunked(obj);
                        }
                    }
                }
            }
            //checks player collision against enemies
        }

        public void UpdatePlayers(Microsoft.Xna.Framework.GameTime gameTime)
        {
            //updates each player
            protoman.Update(gameTime);
        }

        public void UpdateEnemies(Microsoft.Xna.Framework.GameTime gameTime)
        {
            List<CollidableObject> toAdd = new List<CollidableObject>();
            foreach (CollidableObject obj in enemies)
            {
                calculateTarget((PrototypeEnemy)obj);
                obj.Update(gameTime);
                List<CollidableObject> thisOnesAddList = ((PrototypeEnemy)obj).getMakeList();
                foreach (CollidableObject COtoAdd in thisOnesAddList){
                    toAdd.Add(COtoAdd);
                }
                thisOnesAddList.Clear();
                ((PrototypeEnemy)obj).clearMakeList();
            }
            foreach (CollidableObject obj in toAdd)
            {
                obj.LoadContent(content);
                enemies.Add(obj);
            }
            toAdd.Clear();
        }

        public void calculateTarget(PrototypeEnemy obj)
        {
            if (obj.currentTarget == null)
            {
                //TO DO: CALCULATION FOR TARGET SELECTION
                //ATM: Just protoman
                obj.currentTarget = protoman;
            }
        }

        public void UpdateProjectiles(Microsoft.Xna.Framework.GameTime gameTime)
        {
            foreach (CollidableObject obj in projectiles)
            {
                obj.Update(gameTime);
            }
        }

        public void UpdateItemEntities(Microsoft.Xna.Framework.GameTime gameTime)
        {
            //updates item entities
            //removes dead (empty) item entities
        }

        internal void LoadContent(Microsoft.Xna.Framework.Content.ContentManager Content)
        {
            if (content == null)
                content = Content;

            background = content.Load<Texture2D>("background");
            protoman.LoadContent(content);
            LoadEnemies();
        }

        private void LoadEnemies()
        {
            if (content == null) return;
            foreach (CollidableObject obj in enemies)
            {
                obj.LoadContent(content);
            }
        }

        private void LoadItemEntities()
        {
            throw new NotImplementedException();
        }

        private void LoadEnvironment()
        {
            throw new NotImplementedException();
        }

        internal void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            
            UpdatePlayers(gameTime);
            UpdateEnemies(gameTime);
            UpdateItemEntities(gameTime);
            UpdateProjectiles(gameTime);

            //if (enemies.Count == 0)
            //{
            //    currentRoom.Clear();
            //}
        }

        internal void Draw(Microsoft.Xna.Framework.GameTime gameTime, Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(background, Vector2.Zero, Color.WhiteSmoke);

            protoman.Draw(gameTime, spriteBatch);
            foreach (CollidableObject obj in enemies)
            {
                obj.Draw(gameTime, spriteBatch); 
            }
            foreach (CollidableObject obj in projectiles)
            {
                obj.Draw(gameTime, spriteBatch); 
            }
        }

        public void SetEnemies(List<CollidableObject> enemyList, Boolean clear = true)
        {
            if (clear)
                enemies = enemyList;
            //else
                //enemies.Concat<CollidableObject>(enemyList);

            LoadEnemies();           
        }

        public void SetItemEntities(List<CollidableObject> item_entities)
        {
            //throw new NotImplementedException();
        }

        public void SetEnvironment(List<CollidableObject> environment)
        {
            //throw new NotImplementedException();
        }

        public void SetRoom(Room room)
        {
            currentRoom = room;
        }

        internal bool debugPlayerTravelled(int p)
        {
            switch (p)
            {
                case 1:
                    return protoman.Position.Y < 0;
                case 2:
                    return protoman.Position.Y > 768;
                case 3:
                    return protoman.Position.X > 1024;
                case 4:
                    return protoman.Position.X < 0;
                default:
                    return false;
            }
        }

        internal void ReplacePlayer(int p)
        {
            switch (p)
            {
                case 1:
                    protoman.Position = new Vector2(500, 10);
                    break;
                case 2:
                    protoman.Position = new Vector2(500, 668);
                    break;
                case 3:
                    protoman.Position = new Vector2(924, 500);
                    break;
                case 4:
                    protoman.Position = new Vector2(100, 500);
                    break;
            }
        }
    }
}
